package com.codingman.mybatisdemo1;

import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class SqlMapTemplate {
	private final SqlSessionFactory sqlSessionFactory;
	private final SqlSession sqlSessionProxy;

	private SqlMapTemplate(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionFactory = sqlSessionFactory;
		this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),
				new Class[] { SqlSession.class }, new SqlSessionInterceptor());
	}

	public <T> T getMapper(Class<T> type) {
		return this.sqlSessionFactory.getConfiguration().getMapper(type, this.sqlSessionProxy);
	}

	public static SqlMapTemplate newInstance(InputStream inputStream) {
		return new SqlMapTemplate(new SqlSessionFactoryBuilder().build(inputStream, null, null));
	}

	private class SqlSessionInterceptor implements InvocationHandler {

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

			try (SqlSession autoSqlSession = SqlMapTemplate.this.sqlSessionFactory.openSession()) {
				try {
					final Object result = method.invoke(autoSqlSession, args);
					autoSqlSession.commit();
					return result;
				} catch (Throwable t) {
					autoSqlSession.rollback();
					throw new RuntimeException();
				}
			}
		}
	}
}
